package state

import . "api"

// [-0, +1, m]
// http://www.lua.org/manual/5.3/manual.html#lua_newthread
// lua-5.3.4/src/lstate.c#lua_newthread()
// 创建一个新的线程, 把它推入栈顶
// 同时作为返回值返回
// 新创建的线程和创建它的线程共享相同的全局变量
// 但是有各自的调用栈
// 新创建的线程处于挂起状态
func (self *luaState) NewThread() LuaState {
	t := &luaState{registry: self.registry}
	t.pushLuaStack(newLuaStack(LUA_MINSTACK, t))
	self.stack.push(t)
	return t
}


// [-?, +?, –]
// http://www.lua.org/manual/5.3/manual.html#lua_resume
// 让挂起的协程进入运行状态
// 两个线程通过彼此的coChan字段来相互协作
// 所以需要在首次用到这个字段时进行初始化
// 对于将要进入运行状态的线程
// 如果其coChan字段是nil, 说明是首次开始运行, 需要启动一个Go语言协程(Goroutine)来执行其主函数
// 否则, 线程恢运行, 往它的coChan里随便写入一个值即可
// 不管线程是首次还是恢复运行, 从它的coChan里接收一个值可以等待它执行结束或者挂起
func (self *luaState) Resume(from LuaState, nArgs int) int {
	lsFrom := from.(*luaState)
	if lsFrom.coChan == nil {
		lsFrom.coChan = make(chan int)
	}

	if self.coChan == nil {
		// start coroutine
		self.coChan = make(chan int)
		self.coCaller = lsFrom
		go func() {
			self.coStatus = self.PCall(nArgs, -1, 0)  // 返回执行结果,LUA_ERRRUN或者LUA_OK
			lsFrom.coChan <- 1  // 书籍有误, 这里必须主动去解锁主线程, 否则会一直卡住
		}()
	} else {
		// resume coroutine
		if self.coStatus != LUA_YIELD {  // todo
			self.stack.push("cannot resume non-suspended coroutine")
			return LUA_ERRRUN
		}
		self.coStatus = LUA_OK
		self.coChan <- 1
	}

	<-lsFrom.coChan	// wait coroutine to finish or yield // TODO finish会解除阻塞吗?
	return self.coStatus
}


// [-?, +?, e]
// http://www.lua.org/manual/5.3/manual.html#lua_yield
// 挂起线程
// 首先把线程的状态设置为挂起
// 然后通知协作方恢复运行
// 最后等待再一次恢复运行
func (self *luaState) Yield(nResults int) int {
	if self.coCaller == nil {	// todo
		panic("attempt yied from outside a coroutine")
	}
	self.coStatus = LUA_YIELD
	self.coCaller.coChan <- 1
	<-self.coChan
	return self.GetTop()
}


// [-0, +0, –]
// http://www.lua.org/manual/5.3/manual.html#lua_isyieldable
func (self *luaState) IsYieldable() bool {
	// 主线程不可以被yield TODO ?
	if self.isMainThread() {
		return false
	}
	return self.coStatus != LUA_YIELD 	// todo
}


// [-0, +0, –]
// http://www.lua.org/manual/5.3/manual.html#lua_status
// lua-5.3.4/src/lapi.c#lua_status()
// 返回线程的当前状态
// 这个状态保存在coStatus字段里
// 它的值可能是LUA_OK(正常状态)、LUA_YIELD(挂起状态)或者某种错误码(表示执行过程中遇到了某种错误)
func (self *luaState) Status() int {
	return self.coStatus
}


// 返回线程是否还在执行当中(还有调用栈), 用于调试
func (self *luaState) GetStack() bool {
	return self.stack.prev != nil
}